﻿using System;
using System.Collections.Generic;
using System.Linq;
using BaseDomainNamespace.Builders;

namespace MainDomainNamespace.Entity1s
{
    partial class Entity1
    {
        /// <summary>
        /// <see cref="Entity1"/> のビルダです。
        /// </summary>
        [Serializable]
        public sealed class Builder : EntityBuilder<Entity1, IBuildErrorHandler, IConstraintValidator>
        {
            /// <summary>
            /// <see cref="Entity1.Name">Entity1 の名前</see>の文字数の最大値を取得します。
            /// </summary>
            public static readonly int NameMaxLength = 100;


            /// <summary>
            /// <see cref="Entity1"/> の作成を目的として、<see cref="Builder"/> クラスの新しいインスタンスを初期化します。
            /// </summary>
            /// <param name="validator">制約検証オブジェクト。</param>
            /// <exception cref="System.ArgumentNullException">validator が null です。</exception>
            public Builder(IConstraintValidator validator)
                : base(validator)
            {
            }

            /// <summary>
            /// <see cref="Entity1"/> の編集を目的として、<see cref="Builder"/> クラスの新しいインスタンスを初期化します。
            /// </summary>
            /// <param name="target">編集対象の <see cref="Entity1"/>。</param>
            /// <param name="validator">制約検証オブジェクト。</param>
            /// <exception cref="System.ArgumentNullException">target または validator が null です。</exception>
            public Builder(Entity1 target, IConstraintValidator validator)
                : base(target, validator)
            {
                Name = Target.Name;
            }


            /// <summary>
            /// <see cref="Entity1.Name">Entity1 の名前</see>に指定する値を取得または設定します。
            /// </summary>
            public string Name
            {
                get;
                set;
            }


            /// <summary>
            /// ビルダの現在のエラーを通知します。エラーが無い場合はハンドラには何も通知されません。
            /// </summary>
            /// <param name="handler">エラーハンドラ。</param>
            /// <exception cref="System.ArgumentNullException">handler が null です。</exception>
            public override void NotifyErrorTo(IBuildErrorHandler handler)
            {
                if (handler == null)
                {
                    throw new ArgumentNullException("handler");
                }

                NotifyNameErrorTo(handler);
            }

            /// <summary>
            /// <see cref="Entity1.Name">Entity1 の名前</see>に関するエラーを通知します。エラーが無い場合はハンドラには何も通知されません。
            /// </summary>
            /// <param name="handler">エラーハンドラ。</param>
            /// <exception cref="System.ArgumentNullException">handler が null です。</exception>
            public void NotifyNameErrorTo(INameErrorHandler handler)
            {
                if (handler == null)
                {
                    throw new ArgumentNullException("handler");
                }

                if (string.IsNullOrWhiteSpace(Name))
                {
                    handler.HandleNameEmptyError();
                }
                if ((Name != null) && (NameMaxLength < Name.Length))
                {
                    handler.HandleNameTooLongError();
                }
                if (IsForCreation || (!string.Equals(Target.Name, Name, StringComparison.OrdinalIgnoreCase)))
                {
                    if ((Name != null) && (!Validator.NameIsUnique(Name)))
                    {
                        handler.HandleNameDuplicationError();
                    }
                }
            }


            /// <summary>
            /// <see cref="Entity1"/> をビルドします。
            /// </summary>
            /// <returns>ビルドされた <see cref="Entity1"/>。</returns>
            /// <exception cref="System.InvalidOperationException"><see cref="Entity1"/> をビルドできる状態ではありません。</exception>
            public override Entity1 Build()
            {
                if (!IsValid)
                {
                    throw new InvalidOperationException();
                }

                var result = IsForCreation ? new Entity1() : Target;

                result.Name = Name;

                return result;
            }
        }
    }
}
